#ifndef _GAME_FLOW_MANAGER_H_
#define _GAME_FLOW_MANAGER_H_


#include "num/named_set.h"
#include "game_state.h"
#include <vector>
#include "transition.h"
#include "ui/ui_mover.h"
class Application;

namespace LuaPlus
{
    class LuaState;
}

namespace camera
{
	class FbCamera;
}

namespace ui
{
	class UIWidget;
}

namespace gameflow
{
class UIPopup;
class GameFlowManager : public num::NamedSet<GameState*>
{
public:
    static GameFlowManager&	Instance();

    
    void                SetIsPause(bool b) { m_IsPause = b; };
	/// update the timer
	void				Tick(float dt);
	/// Render is automatically called by Tick, but it can also be called independently
	void				Render();

	/// terminate the current game state
	void				Shutdown();

	/// transition to a new state in N seconds. Will overwrite any previously \n
	/// scheduled state
	void				SetTransitionEffect(const std::string& Effect, const std::string& State, const std::string& Script, GameTransition::TransitionEvent	OnFinish = NULL);

	/// add a new state to the set
	GameState*			AddTransitionState(const std::string& Name, GameState* pNewState);
	
	// Jump to this state later
	void				TransitionToState(const std::string& Name, float Delay = 0.0f);

	/// accessors
	GameState*			GetTransitionState() const { return m_pTransitionState; };
	GameState*			GetCurrentState() const { return m_pCurrentState; };
	GameState*			GetPreviousState() const { return m_pPreviousState; };

	const std::string&	GetCurrentStateName() const;
	const std::string&	GetLastStateName() const;


	GameState*			GetStateByName(const std::string n) const { return GetElement(n); };

	camera::FbCamera*	GetCamera() const { return m_pCamera; };
	void				SetCamera(camera::FbCamera* pCam) { m_pCamera = pCam; };
	void				SetTimePerFrame(float f) { m_TimePerFrame = f; };
	void				SetLastGainFocus(float f) { m_LastGainFocus = f; };
	bool				IsActive();

	TransitionManager&	GetTransition() { return m_Transition; };


	void				AddDelayedScript(const std::string& Script, float Delay = 0.0f, const std::string& ID = "");
	void				RemoveDelayedScript(const std::string& Script);
	void				ClearDelayedScript(const std::string& ID = "");
	bool				HasDelayedScript() const { return !m_DelayedScripts.empty(); }
    /**
     *  Allow a script state to share the Console LUABind functionality
     *  @param  _pScript   Script to register in
     */
     static void           Register(LuaPlus::LuaState* _pScript);

	virtual void		DPadNav(int	DirX, int DirY, int	Triggered);

	typedef void (*CustomTickCB)(float dt);
	void				SetCustomTick(CustomTickCB pCB) { m_pCustomTickCB = pCB; };

	bool				InTransition() const { return m_pTransitionState != NULL; };
	 // to stop luabind from bitching
                       ~GameFlowManager();
private:
                        GameFlowManager();


	/// transition to a new state with no delay
	void				JumpToState(const std::string& Name);
	void				JumpToState(GameState* pNewState);


	camera::FbCamera*	m_pCamera;

    /// Not implemented to prevent copying
    GameFlowManager( const GameFlowManager & );     
    GameFlowManager& operator=( const GameFlowManager & );

	// timing
	float				m_TimePerFrame;
	float				m_TimeSinceLastFrame;
	float				m_MaxDeltaTime;

	/// current state
	GameState*			m_pCurrentState;
	/// the state we were in before this
	GameState*			m_pPreviousState;

	/// if we're asking the system to transition, this contains the transition state
	GameState*			m_pTransitionState;
	float				m_TransitionTime;

	// used for transitions
	TransitionManager	m_Transition;		
	float				m_LastGainFocus;
	CustomTickCB		m_pCustomTickCB;

	struct				DelayedScript
	{
		float			Delta;
		std::string		Script;
		std::string		ID;
	};
	std::vector<DelayedScript>	m_DelayedScripts;


	float				m_Render_dt;
    bool                m_IsPause;
    

};

};	// namespace num

#define GAMEFLOW()	gameflow::GameFlowManager::Instance()

#endif // _GAME_FLOW_MANAGER_H_